package com.qfmy.app.aop;


import com.qfmy.app.service.common.LogService;
import com.qfmy.common.utils.JwtUtil;
import com.qfmy.model.annotation.LogAnnotation;
import com.qfmy.model.entity.common.Log;
import io.jsonwebtoken.Claims;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;

/**
 * @author 清风明月
 * @Package com.qfmy.app.aop
 * @date 2025/4/13
 * @description 记录日志的切面类
 */
@Component
@Aspect
@SuppressWarnings("all")
public class LogAspect {
    /**
     * 注入LogService
     */
    @Resource
    private LogService logService;

    /**
     * 编写切点
     */
    @Pointcut("@annotation(com.qfmy.model.annotation.LogAnnotation)")
    public void pt(){};

    @Around("pt()")
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        // 拿到请求对象Request
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        // 获取 token
        String accessToken = request.getHeader("access-token");
        //判断 token是否获取成功
        if(accessToken.isEmpty()){
            return joinPoint.proceed();
        }
        // 解析 token
        Claims claims = JwtUtil.parseToken(accessToken);
        // 获取用户名
        String username = claims.get("username").toString();
        // 获取方法的注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
        String operateName = logAnnotation.operation();
        // 记录开始时间
        long start = System.currentTimeMillis();

        // 提前创建日志对象
        Log log = createLog(operateName, username);
        try {
            // 执行目标方法
            Object result = joinPoint.proceed();
            // 记录结束时间
            long end = System.currentTimeMillis();
            // 设置成功状态
            log.setTime(end - start);
            log.setOperateResult(true);
            // 保存日志
            saveLog(log);
            return result;
        } catch (Exception e) {
            // 记录结束时间
            long end = System.currentTimeMillis();

            // 设置失败状态
            log.setTime(end - start);
            log.setOperateResult(false);
            log.setOperateFailReason(e.getMessage());
            // 记录异常堆栈信息
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            log.setOperateFailReason(sw.toString());

            // 保存日志
            saveLog(log);

            throw e;
        }
    }

    /**
     * 创建日志对象并设置公共属性
     */
    private Log createLog(String operateName, String username) {
        Log log = new Log();
        log.setOperateName(operateName);
        log.setUsername(username);
        return log;
    }

    /**
     * 保存日志（可以是数据库、文件或其他存储方式）
     */
    private void saveLog(Log log) {
        logService.saveLog(log);
    }

}
